/* * This file is part of Bitsquare. * * Bitsquare is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * Bitsquare is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Bitsquare. If not, see <http://www.gnu.org/licenses/>. */ package io.bitsquare.gui.main.portfolio.openoffer; import io.bitsquare.btc.FeePolicy; import io.bitsquare.gui.Navigation; import io.bitsquare.gui.common.view.ActivatableViewAndModel; import io.bitsquare.gui.common.view.FxmlView; import io.bitsquare.gui.components.HyperlinkWithIcon; import io.bitsquare.gui.main.MainView; import io.bitsquare.gui.main.funds.FundsView; import io.bitsquare.gui.main.funds.withdrawal.WithdrawalView; import io.bitsquare.gui.main.overlays.popups.Popup; import io.bitsquare.gui.main.overlays.windows.OfferDetailsWindow; import io.bitsquare.trade.offer.OpenOffer; import io.bitsquare.user.Preferences; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.transformation.SortedList; import javafx.fxml.FXML; import javafx.scene.control.*; import javafx.scene.image.ImageView; import javafx.scene.layout.VBox; import javafx.util.Callback; import org.bitcoinj.utils.Fiat; import javax.inject.Inject; @FxmlView public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersViewModel> { @FXML TableView<OpenOfferListItem> tableView; @FXML TableColumn<OpenOfferListItem, OpenOfferListItem> priceColumn, amountColumn, volumeColumn, marketColumn, directionColumn, dateColumn, offerIdColumn, removeItemColumn; private final Navigation navigation; private final OfferDetailsWindow offerDetailsWindow; private Preferences preferences; private SortedList<OpenOfferListItem> sortedList; @Inject public OpenOffersView(OpenOffersViewModel model, Navigation navigation, OfferDetailsWindow offerDetailsWindow, Preferences preferences) { super(model); this.navigation = navigation; this.offerDetailsWindow = offerDetailsWindow; this.preferences = preferences; } @Override public void initialize() { setOfferIdColumnCellFactory(); setDirectionColumnCellFactory(); setMarketColumnCellFactory(); setPriceColumnCellFactory(); setAmountColumnCellFactory(); setVolumeColumnCellFactory(); setDateColumnCellFactory(); setRemoveColumnCellFactory(); tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); tableView.setPlaceholder(new Label("No open offers available")); offerIdColumn.setComparator((o1, o2) -> o1.getOffer().getId().compareTo(o2.getOffer().getId())); directionColumn.setComparator((o1, o2) -> o1.getOffer().getDirection().compareTo(o2.getOffer().getDirection())); marketColumn.setComparator((o1, o2) -> model.getMarketLabel(o1).compareTo(model.getMarketLabel(o2))); amountColumn.setComparator((o1, o2) -> o1.getOffer().getAmount().compareTo(o2.getOffer().getAmount())); priceColumn.setComparator((o1, o2) -> { Fiat price1 = o1.getOffer().getPrice(); Fiat price2 = o2.getOffer().getPrice(); return price1 != null && price2 != null ? price1.compareTo(price2) : 0; }); volumeColumn.setComparator((o1, o2) -> { Fiat offerVolume1 = o1.getOffer().getOfferVolume(); Fiat offerVolume2 = o2.getOffer().getOfferVolume(); return offerVolume1 != null && offerVolume2 != null ? offerVolume1.compareTo(offerVolume2) : 0; }); dateColumn.setComparator((o1, o2) -> o1.getOffer().getDate().compareTo(o2.getOffer().getDate())); dateColumn.setSortType(TableColumn.SortType.DESCENDING); tableView.getSortOrder().add(dateColumn); } @Override protected void activate() { sortedList = new SortedList<>(model.getList()); sortedList.comparatorProperty().bind(tableView.comparatorProperty()); tableView.setItems(sortedList); } @Override protected void deactivate() { sortedList.comparatorProperty().unbind(); } private void onRemoveOpenOffer(OpenOffer openOffer) { if (model.isBootstrapped()) { String key = "RemoveOfferWarning"; if (preferences.showAgain(key)) new Popup().warning("Are you sure you want to remove that offer?\n" + "The offer fee of " + model.formatter.formatCoinWithCode(FeePolicy.getCreateOfferFee()) + " will be lost if you remove that offer.") .actionButtonText("Remove offer") .onAction(() -> doRemoveOpenOffer(openOffer)) .closeButtonText("Don't remove the offer") .dontShowAgainId(key, preferences) .show(); else doRemoveOpenOffer(openOffer); } else { new Popup().information("You need to wait until you are fully connected to the network.\n" + "That might take up to about 2 minutes at startup.").show(); } } private void doRemoveOpenOffer(OpenOffer openOffer) { model.onCancelOpenOffer(openOffer, () -> { log.debug("Remove offer was successful"); String key = "WithdrawFundsAfterRemoveOfferInfo"; if (preferences.showAgain(key)) new Popup().instruction("You can withdraw the funds you paid in from the \"Fund/Available for withdrawal\" screen.") .actionButtonText("Go to \"Funds/Available for withdrawal\"") .onAction(() -> navigation.navigateTo(MainView.class, FundsView.class, WithdrawalView.class)) .dontShowAgainId(key, preferences) .show(); }, (message) -> { log.error(message); new Popup().warning("Remove offer failed:\n" + message).show(); }); } private void setOfferIdColumnCellFactory() { offerIdColumn.setCellValueFactory((openOfferListItem) -> new ReadOnlyObjectWrapper<>(openOfferListItem.getValue())); offerIdColumn.setCellFactory( new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { @Override public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem, OpenOfferListItem> column) { return new TableCell<OpenOfferListItem, OpenOfferListItem>() { private HyperlinkWithIcon field; @Override public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); if (item != null && !empty) { field = new HyperlinkWithIcon(model.getTradeId(item), true); field.setOnAction(event -> offerDetailsWindow.show(item.getOffer())); field.setTooltip(new Tooltip("Open popup for details")); setGraphic(field); } else { setGraphic(null); if (field != null) field.setOnAction(null); } } }; } }); } private void setDateColumnCellFactory() { dateColumn.setCellValueFactory((openOfferListItem) -> new ReadOnlyObjectWrapper<>(openOfferListItem.getValue())); dateColumn.setCellFactory( new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { @Override public TableCell<OpenOfferListItem, OpenOfferListItem> call( TableColumn<OpenOfferListItem, OpenOfferListItem> column) { return new TableCell<OpenOfferListItem, OpenOfferListItem>() { @Override public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); if (item != null) setText(model.getDate(item)); else setText(""); } }; } }); } private void setAmountColumnCellFactory() { amountColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); amountColumn.setCellFactory( new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { @Override public TableCell<OpenOfferListItem, OpenOfferListItem> call( TableColumn<OpenOfferListItem, OpenOfferListItem> column) { return new TableCell<OpenOfferListItem, OpenOfferListItem>() { @Override public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); setText(model.getAmount(item)); } }; } }); } private void setPriceColumnCellFactory() { priceColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); priceColumn.setCellFactory( new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { @Override public TableCell<OpenOfferListItem, OpenOfferListItem> call( TableColumn<OpenOfferListItem, OpenOfferListItem> column) { return new TableCell<OpenOfferListItem, OpenOfferListItem>() { @Override public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); setText(model.getPrice(item)); } }; } }); } private void setVolumeColumnCellFactory() { volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); volumeColumn.setCellFactory( new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { @Override public TableCell<OpenOfferListItem, OpenOfferListItem> call( TableColumn<OpenOfferListItem, OpenOfferListItem> column) { return new TableCell<OpenOfferListItem, OpenOfferListItem>() { @Override public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); if (item != null) setText(model.getVolume(item)); else setText(""); } }; } }); } private void setDirectionColumnCellFactory() { directionColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); directionColumn.setCellFactory( new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { @Override public TableCell<OpenOfferListItem, OpenOfferListItem> call( TableColumn<OpenOfferListItem, OpenOfferListItem> column) { return new TableCell<OpenOfferListItem, OpenOfferListItem>() { @Override public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); setText(model.getDirectionLabel(item)); } }; } }); } private void setMarketColumnCellFactory() { marketColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); marketColumn.setCellFactory( new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { @Override public TableCell<OpenOfferListItem, OpenOfferListItem> call( TableColumn<OpenOfferListItem, OpenOfferListItem> column) { return new TableCell<OpenOfferListItem, OpenOfferListItem>() { @Override public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); setText(model.getMarketLabel(item)); } }; } }); } private void setRemoveColumnCellFactory() { removeItemColumn.setCellValueFactory((offerListItem) -> new ReadOnlyObjectWrapper<>(offerListItem.getValue())); removeItemColumn.setCellFactory( new Callback<TableColumn<OpenOfferListItem, OpenOfferListItem>, TableCell<OpenOfferListItem, OpenOfferListItem>>() { @Override public TableCell<OpenOfferListItem, OpenOfferListItem> call(TableColumn<OpenOfferListItem, OpenOfferListItem> column) { return new TableCell<OpenOfferListItem, OpenOfferListItem>() { final ImageView iconView = new ImageView(); final Button button = new Button(); { iconView.setId("image-remove"); button.setText("Remove"); button.setGraphic(iconView); button.setMinWidth(70); } @Override public void updateItem(final OpenOfferListItem item, boolean empty) { super.updateItem(item, empty); if (item != null) { button.setOnAction(event -> onRemoveOpenOffer(item.getOpenOffer())); setGraphic(button); } else { setGraphic(null); } } }; } }); } }